package com.dstz.bpm.api.engine.context;

import com.dstz.base.api.exception.BusinessException;
import com.dstz.base.core.util.StringUtil;
import com.dstz.bpm.api.engine.action.cmd.ActionCmd;
import com.dstz.bpm.api.exception.BpmStatusCode;
import com.dstz.bpm.api.model.def.BpmProcessDef;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

public class BpmContext {
   private static ThreadLocal<Stack<ActionCmd>> threadActionModel = new ThreadLocal();
   private static ThreadLocal<Map<String, BpmProcessDef>> threadBpmProcessDef = new ThreadLocal();

   public static void setActionModel(ActionCmd actionModel) {
      if (actionModel != null && !StringUtil.isEmpty(actionModel.getActionName())) {
         getStack(threadActionModel).push(actionModel);
      } else {
         throw new BusinessException("set thread actionModel error , actionModel canot be null", BpmStatusCode.ACTIONCMD_ERROR);
      }
   }

   public static ActionCmd getActionModel() {
      Stack<ActionCmd> stack = getStack(threadActionModel);
      return stack.isEmpty() ? null : (ActionCmd)stack.peek();
   }

   public static ActionCmd submitActionModel() {
      Stack<ActionCmd> stack = getStack(threadActionModel);
      return stack.isEmpty() ? null : (ActionCmd)stack.firstElement();
   }

   public static void removeActionModel() {
      Stack stack = getStack(threadActionModel);
      if (!stack.isEmpty()) {
         stack.pop();
      }

   }

   public static BpmProcessDef getProcessDef(String defId) {
      Map<String, BpmProcessDef> map = getThreadMap(threadBpmProcessDef);
      return (BpmProcessDef)map.get(defId);
   }

   public static void addProcessDef(String defId, BpmProcessDef processDef) {
      getThreadMap(threadBpmProcessDef).put(defId, processDef);
   }

   public static void cleanTread() {
      threadActionModel.remove();
      threadBpmProcessDef.remove();
   }

   protected static <T> Stack<T> getStack(ThreadLocal<Stack<T>> threadLocal) {
      Stack<T> stack = (Stack)threadLocal.get();
      if (stack == null) {
         stack = new Stack();
         threadLocal.set(stack);
      }

      return stack;
   }

   protected static <T> Map<String, T> getThreadMap(ThreadLocal<Map<String, T>> threadMap) {
      Map<String, T> processDefMap = (Map)threadMap.get();
      if (processDefMap == null) {
         processDefMap = new HashMap();
         threadMap.set(processDefMap);
      }

      return (Map)processDefMap;
   }
}
